package cc.magicjson.example.demo.exam;

import java.util.LinkedList;
import java.util.List;

/**
 * 使用LinkedList实现安全Queue
 * <p>
 * {@link LinkedList}
 *
 * @author <a href="mailto:it_magicjson@163.com">MagicJson</a>
 * @since 1.0.0
 */
public class ThreadSafeQueue<T> {
	// 考虑频繁添删 使用LinkedList作为底层数据结构
	private final List<T> queue = new LinkedList<>();

	/**
	 * 向队列中添加一个元素
	 *
	 * @param element 要添加的元素
	 */
	public synchronized void add(T element) {
		queue.add(element);
		// 通知所有等待的线程新元素已加入队列
		notifyAll();
	}

	/**
	 * 移除并返回队列头部的元素
	 *
	 * @return 队列头部的元素
	 * @throws InterruptedException 如果等待时被中断
	 */
	public synchronized T remove() throws InterruptedException {
		while (queue.isEmpty()) {
			// 如果队列为空，则等待
			wait();
		}
		// 移除并返回队列头部的元素
		return queue.remove(0);
	}

	/**
	 * 返回队列的大小
	 *
	 * @return 队列中元素的数量
	 */
	public synchronized int size() {
		return queue.size();
	}

	public static void main(String[] args) {
		ThreadSafeQueue<Integer> tsQueue = new ThreadSafeQueue<>();

		// 创建生产者线程
		Runnable producer = () -> {
			for (int i = 0; i < 100; i++) {
				tsQueue.add(i);
				System.out.println("Produced: " + i);
				try {
					// 模拟生产时间
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// 处理中断
					Thread.currentThread().interrupt();
				}
			}
		};

		// 创建消费者线程
		Runnable consumer = () -> {
			for (int i = 0; i < 100; i++) {
				try {
					int item = tsQueue.remove();
					System.out.println("Consumed: " + item);
				} catch (InterruptedException e) {
					// 处理中断
					Thread.currentThread().interrupt();
				}
				try {
					// 模拟消费时间
					Thread.sleep(150);
				} catch (InterruptedException e) {
					// 处理中断
					Thread.currentThread().interrupt();
				}
			}
		};

		// 启动生产者线程和消费者线程
		Thread producerThread = new Thread(producer);
		Thread consumerThread = new Thread(consumer);

		producerThread.start();
		consumerThread.start();

		try {
			// 等待生产者线程结束
			producerThread.join();
			// 等待消费者线程结束
			consumerThread.join();
		} catch (InterruptedException e) {
			// 处理中断
			Thread.currentThread().interrupt();
		}
	}
}
